var Amqp = require('../api/amqp').Amqp,
    Handler = require('../handlers/consumer').Consumer;
/**
 *
 * @class
 * @extends events.EventEmitter
 * @exports File as impl.File
 * @param {Channel} handler
 */
function File(/**handlers.Channel*/handler){
    var file = this;
    this.handler = handler;
    /**
     * Confirm the requested qos.
     *
     * This method tells the client that the requested QoS levels could be handled by the server.
     * The requested QoS applies to all active consumers until a new QoS is defined.
     *
     * @name File#qos
     * @event
     */
    handler.addListener('Amqp.File.QosOk', function(){
        file.emit('qos');
    });
    /**
     * Confirm a new consumer.
     *
     * This method provides the client with a consumer tag which it MUST use in methods that work
     * with the consumer.
     *
     * @name File#consume
     * @event
     * @param {String} consumerTag Identifier for the consumer, valid within the current
     *      connection.
     */
    handler.addListener('Amqp.File.ConsumeOk', function(frame){
        file.emit('consume', frame.method.arguments.consumerTag);
    });
    /**
     * Confirm a cancelled consumer.
     *
     * This method confirms that the cancellation was completed.
     *
     * @name File#cancel
     * @event
     * @param {String} consumerTag Identifier for the consumer, valid within the current
     *      connection.
     */
    handler.addListener('Amqp.File.CancelOk', function(frame){
        file.emit('cancel', frame.method.arguments.consumerTag);
    });
    /**
     * Confirm staging ready.
     *
     * This method confirms that the recipient is ready to accept staged data. If the message was
     * already partially-staged at a previous time the recipient will report the number of octets
     * already staged.
     *
     * @name File#outgoing
     * @event
     * @param {Number} stagedSize The amount of previously-staged content in octets. For a new
     *      message this will be zero.
     */
    handler.addListener('Amqp.File.OpenOk', function(frame){
        this.call(Amqp.Class.File, Amqp.Class.File.Stage);
        file.emit('outgoing', frame.method.arguments.stagedSize);
    });
    /**
     * Request to start staging.
     *
     * This method requests permission to start staging a message. Staging means sending the
     * message into a temporary area at the recipient end and then delivering the message by
     * referring to this temporary area. Staging is how the protocol handles partial file
     * transfers - if a message is partially staged and the connection breaks, the next time the
     * sender starts to stage it, it can restart from where it left off.
     *
     * @name File#incoming
     * @param {String} identifier This is the staging identifier. This is an arbitrary string
     *      chosen by the sender. For staging to work correctly the sender must use the same
     *      staging identifier when staging the same message a second time after recovery from a
     *      failure. A good choice for the staging identifier would be the SHA1 hash of the message
     *      properties data (including the original filename, revised time, etc.).
     * @param {Number} contentSize The size of the content in octets. The recipient may use this
     *      information to allocate or check available space in advance, to avoid "disk full"
     *      errors during staging of very large messages.
     */
    handler.addListener('Amqp.File.Open', function(frame){
        var a = frame.method.arguments;
        file.emit('incoming', a.identifier, a.contentSize);
    });
    /**
     * Stage message content.
     *
     * This method stages the message, sending the message content to the recipient from the octet
     * offset specified in the <code>outgoing</code> method.
     *
     * @name File#stage
     * @event
     */
    handler.addListener('Amqp.File.Stage', function(){
        file.emit('stage');
    });
    /**
     * Notify the client of a consumer message.
     *
     * This method delivers a staged file message to the client, via a consumer. In the
     * asynchronous message delivery model, the client starts a consumer using the Consume method,
     * then the server responds with Deliver methods as and when messages arrive for that consumer.
     *
     * @name File#deliver
     * @event
     * @param {String} consumerTag Identifier for the consumer, valid within the current
     *      connection.
     * @param {Number} deliveryTag The server-assigned and channel-specific delivery tag.
     * @param {Boolean} redelivered This indicates that the message has been previously delivered
     *      to this or another client.
     * @param {String} exchange The exchange name is a client-selected string that identifies the
     *      exchange for publish methods. Exchange names may consist of any mixture of digits,
     *      letters, and underscores. Exchange names are scoped by the virtual host.
     * @param {String} routingKey Specifies the routing key name specified when the message was
     *      published.
     * @param {String} identifier This is the staging identifier of the message to deliver. The
     *      message must have been staged. Note that a server can send the Deliver method
     *      asynchronously without waiting for staging to finish.
     * @param {impl.File.Fields} fields
     * @param {String} body
     */
    handler.addListener('Amqp.File.Deliver', function(frame){
        var a = frame.method.arguments;
        file.emit('deliver', a.consumerTag, a.deliveryTag, a.redelivered, a.exchange, a.routingKey,
                a.identifier, frame.method.fields, frame.body);
    });
    /**
     * Return a failed message.
     *
     * This method returns an undeliverable message that was published with the "immediate" flag
     * set, or an unroutable message published with the "mandatory" flag set. The reply code and
     * text provide information about the reason that the message was undeliverable.
     *
     * @nameFile#return
     * @event
     * @param {Number} replyCode The reply code. The AMQ reply codes are defined in AMQ RFC 011.
     * @param {String} replyText The localised reply text. This text can be logged as an aid to
     *      resolving issues.
     * @param {String} exchange The exchange name is a client-selected string that identifies the
     *      exchange for publish methods. Exchange names may consist of any mixture of digits,
     *      letters, and underscores. Exchange names are scoped by the virtual host.
     * @param {String} routingKey Specifies the routing key name specified when the message was
     *      published.
     */
    handler.addListener('Amqp.File.Return', function(frame){
        var a = frame.method.arguments;
        file.emit('return', a.replyCode, a.replyText, a.exchange, a.routingKey);
    });
}
require('sys').inherits(File, require('events').EventEmitter);
/**
 * Acknowledge one or more messages.
 *
 * This method acknowledges one or more messages delivered via the Deliver method. The client can
 * ask to confirm a single message or a set of messages up to and including a specific message.
 *
 * @param {Object} args
 * @param {Number} args.deliveryTag The server-assigned and channel-specific delivery tag
 * @param {Boolean} args.multiple If set to 1, the delivery tag is treated as "up to and
 *      including", so that the client can acknowledge multiple messages with a single method. If
 *      set to zero, the delivery tag refers to a single message. If the multiple field is 1, and
 *      the delivery tag is zero, tells the server to acknowledge all outstanding mesages.
 */
File.prototype.ack = function(args){
    this.handler.call(Amqp.Class.File, Amqp.Class.File.Ack, args);
};
/**
 * End a queue consumer.
 *
 * This method cancels a consumer. This does not affect already delivered messages, but it does
 * mean the server will not send any more messages for that consumer.
 *
 * @param {Object} args
 * @param {String} args.consumerTag Identifier for the consumer, valid within the current connection.
 * @param {Boolean} args.nowait If set, the server will not respond to the method. The client should not wait for a reply method. If the server could not complete the method it will raise a channel or connection exception.
 */
File.prototype.cancel = function(args){
    this.handler.call(Amqp.Class.File, Amqp.Class.File.Cancel, args);
};
/**
 * Start a queue consumer.
 *
 * This method asks the server to start a "consumer", which is a transient request for messages
 * from a specific queue. Consumers last as long as the channel they were created on, or until the
 * client cancels them.
 *
 * @param {Object} args
 * @param {Number} args.ticket An access ticket granted by the server for a certain set of access rights within a
 *      specific realm. Access tickets are valid within the channel where they were created, and
 *      expire when the channel closes.
 * @param {String} args.queue The queue name identifies the queue within the vhost. Queue names may consist of
 *      any mixture of digits, letters, and underscores.
 * @param {String} args.consumerTag Identifier for the consumer, valid within the current connection.
 * @param {Boolean} args.noLocal If the no-local field is set the server will not send messages to the client that
 *      published them.
 * @param {Boolean} args.noAck If this field is set the server does not expect acknowledgments for messages. That
 *      is, when a message is delivered to the client the server automatically and silently
 *      acknowledges it on behalf of the client. This functionality increases performance but at
 *      the cost of reliability. Messages can get lost if a client dies before it can deliver them
 *      to the application.
 * @param {Boolean} args.exclusive Request exclusive consumer access, meaning only this consumer can access the
 *      queue.
 * @param {Boolean} args.nowait If set, the server will not respond to the method. The client should not wait for
 *      a reply method. If the server could not complete the method it will raise a channel or
 *      connection exception.
 */
File.prototype.consume = function(args){
    this.handler.call(Amqp.Class.File, Amqp.Class.File.Consume, args);
};
/**
 * Request to start staging.
 *
 * This method requests permission to start staging a message. Staging means sending the message
 * into a temporary area at the recipient end and then delivering the message by referring to this
 * temporary area. Staging is how the protocol handles partial file transfers - if a message is
 * partially staged and the connection breaks, the next time the sender starts to stage it, it can
 * restart from where it left off.
 *
 * @param {Object} args
 * @param {String} args.identifier This is the staging identifier. This is an arbitrary string chosen by the
 *      sender. For staging to work correctly the sender must use the same staging identifier when
 *      staging the same message a second time after recovery from a failure. A good choice for the
 *      staging identifier would be the SHA1 hash of the message properties data (including the
 *      original filename, revised time, etc.).
 * @param {Number} args.contentSize The size of the content in octets. The recipient may use this information to
 *      allocate or check available space in advance, to avoid "disk full" errors during staging of
 *      very large messages.
 */
File.prototype.open = function(args){
    this.handler.call(Amqp.Class.File, Amqp.Class.File.Open, args);
};
/**
 * Confirm staging ready.
 *
 * This method confirms that the recipient is ready to accept staged data. If the message was
 * already partially-staged at a previous time the recipient will report the number of octets
 * already staged.
 *
 * @param {Object} args
 * @param {Number} args.stagedSize The amount of previously-staged content in octets. For a new
 *      message this will be zero.
 */
File.prototype.confirm = function(args){
    this.handler.call(Amqp.Class.File, Amqp.Class.File.OpenOk, args);
};
/**
 * Publish a message.
 *
 * This method publishes a staged file message to a specific exchange. The file message will be
 * routed to queues as defined by the exchange configuration and distributed to any active
 * consumers when the transaction, if any, is committed.
 *
 * @param {Object} args
 * @param {Number} args.ticket An access ticket granted by the server for a certain set of access rights within a
 *      specific realm. Access tickets are valid within the channel where they were created, and
 *      expire when the channel closes.
 * @param {String} args.exchange The exchange name is a client-selected string that identifies the exchange for
 *      publish methods. Exchange names may consist of any mixture of digits, letters, and
 *      underscores. Exchange names are scoped by the virtual host.
 * @param {String} args.routingKey Specifies the routing key for the message. The routing key is used for routing
 *      messages depending on the exchange configuration.
 * @param {Boolean} args.mandatory This flag tells the server how to react if the message cannot be routed to a
 *      queue. If this flag is set, the server will return an unroutable message with a Return
 *      method. If this flag is zero, the server silently drops the message.
 * @param {Boolean} args.immediate This flag tells the server how to react if the message cannot be routed to a
 *      queue consumer immediately. If this flag is set, the server will return an undeliverable
 *      message with a Return method. If this flag is zero, the server will queue the message, but
 *      with no guarantee that it will ever be consumed.
 * @param {String} args.identifier This is the staging identifier of the message to publish. The message must
 *      have been staged. Note that a client can send the Publish method asynchronously without
 *      waiting for staging to finish.
 * @param {Object} fields
 * @param {String} body
 */
File.prototype.publish = function(args, fields, body){
    this.handler.call(Amqp.Class.File, Amqp.Class.File.Open, args, fields, body);
};
/**
 * Specify quality of service.
 *
 * This method requests a specific quality of service. The QoS can be specified for the current
 * channel or for all channels on the connection. The particular properties and semantics of a qos
 * method always depend on the content class semantics. Though the qos method could in principle
 * apply to both peers, it is currently meaningful only for the server.
 *
 * @param {Number} args.prefetchSize The client can request that messages be sent in advance so that when the
 *      client finishes processing a message, the following message is already held locally, rather
 *      than needing to be sent down the channel. Prefetching gives a performance improvement. This
 *      field specifies the prefetch window size in octets. May be set to zero, meaning "no
 *      specific limit". Note that other prefetch limits may still apply. The prefetch-size is
 *      ignored if the no-ack option is set.
 * @param {Number} args.prefetchCount Specifies a prefetch window in terms of whole messages. This is compatible
 *      with some file API implementations. This field may be used in combination with the
 *      prefetch-size field; a message will only be sent in advance if both prefetch windows (and
 *      those at the channel and connection level) allow it. The prefetch-count is ignored if the
 *      no-ack option is set.
 * @param {Boolean} args.global By default the QoS settings apply to the current channel only. If this field is
 *      set, they are applied to the entire connection.
 */
File.prototype.qos = function(args){
    this.handler.call(Amqp.Class.File, Amqp.Class.File.Qos, args);
};
/**
 * Reject an incoming message.
 *
 * This method allows a client to reject a message. It can be used to return untreatable messages
 * to their original queue. Note that file content is staged before delivery, so the client will
 * not use this method to interrupt delivery of a large message.
 *
 * @param deliveryTag The server-assigned and channel-specific delivery tag.
 * @param requeue If this field is zero, the message will be discarded. If this bit is 1, the
 *      server will attempt to requeue the message.
 */
File.prototype.reject = function(/**String*/deliveryTag, /**Boolean*/requeue){
    this.handler.call(Amqp.Class.File, Amqp.Class.File.Reject, args);
};
/** Stage message content.
 *
 * This method stages the message, sending the message content to the recipient from the octet
 * offset specified in the Open-Ok method. */
File.prototype.stage = function(){
    this.handler.call(Amqp.Class.File, Amqp.Class.File.Stage);
};
exports.File = File;
